﻿using Microsoft.Kinect;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace DetectingKinectSencor
{
    /// <summary>
    /// The following class was provided by the book 
    /// Microsoft.Press.Programming.with.the.Kinect.for.Windows.Software.Development.Kit.Sep.2012
    /// </summary>
    class RecordStreams
    {
        /// <summary>
        /// FlagAttribute defines the three different streams
        /// color = 1
        /// depth = 2
        /// skeleton = 4
        /// </summary>
    
        [FlagsAttribute]
        public enum KinectRecordOptions
        {
            Color = 1,
            Depth = 2,
            Skeletons = 4
        }

        // Stream object
        Stream recordStream;

        // Writer object
        readonly BinaryWriter writer;

        DateTime previousFlushDate;

        // Recorders
        readonly RecordColorStream colorRecoder;
        readonly RecordDepthStream depthRecorder;
        readonly RecordSkeletonStream skeletonRecorder;

        /// <summary>
        /// Defines the getter and setter methods
        /// </summary>
        public KinectRecordOptions Options { get; set; }

        /// <summary>
        /// This is the constructor of the class RecordStreams, with creating an object the options and stream
        /// are transfered and stored in the object. Afterwards can the record method be invoked.
        /// The right record method is chosen by the type of frame.
        /// </summary>
        /// <param name="options"></param>
        /// <param name="stream"></param>
        public RecordStreams(KinectRecordOptions options, Stream stream)
        {
            // Options corrspond to the FlagAttribute
            Options = options;

            // Allocate the transfer parameter to the local recordStream variable
            recordStream = stream;

            writer = new BinaryWriter(recordStream);

            // Write which stream is recorded, see FlagAttribute
            writer.Write((int)Options);

            // Chose which stream should be recorded
            if ((Options & KinectRecordOptions.Color) != 0)
            {
                // Create a new Color stream recorded and safe in the constructor the writer
                colorRecoder = new RecordColorStream(writer);
            }
            if ((Options & KinectRecordOptions.Depth) != 0)
            {
                // Create a new depth stream recorded and safe in the constructor the writer
                depthRecorder = new RecordDepthStream(writer);
            }
            if ((Options & KinectRecordOptions.Skeletons) != 0)
            {
                // Create a new skeleton stream recorded and safe in the constructor the writer
                skeletonRecorder = new RecordSkeletonStream(writer);
            }
        }

        /// <summary>
        /// Record the skeleton stream
        /// </summary>
        /// <param name="frame"></param>
        public void Record(SkeletonFrame frame)
        {
            //Check if the write and the skeletonRecorder exists
            if (writer == null)
                throw new Exception("This recorder is stopped");
            if (skeletonRecorder == null)
                throw new Exception("Skeleton recording is not activated on this KinectRecorder");

            //Record the incoming frames
            skeletonRecorder.Record(frame);
            Flush();
        }

        /// <summary>
        /// Record the color stream
        /// </summary>
        /// <param name="frame"></param>
        public void Record(ColorImageFrame frame)
        {
            //Check if the write and the colorRecorder exists
            if (writer == null)
                throw new Exception("This recorder is stopped");
            if (colorRecoder == null)
                throw new Exception("Color recording is not activated on this KinectRecorder");

            //Record the incoming frames
            colorRecoder.Record(frame);
            Flush();
        }

        /// <summary>
        /// Record the depth stream
        /// </summary>
        /// <param name="frame"></param>
        public void Record(DepthImageFrame frame)
        {
            //Check if the write and the depthRecorder exists
            if (writer == null)
                throw new Exception("This recorder is stopped");
            if (depthRecorder == null)
                throw new Exception("Depth recording is not activated on this KinectRecorder");

            //Record the incoming frames
            depthRecorder.Record(frame);
            Flush();
        }


        void Flush()
        {
            var now = DateTime.Now;

            if (now.Subtract(previousFlushDate).TotalSeconds > 60)
            {
                previousFlushDate = now;
                writer.Flush();
            }
        }


        /// <summary>
        /// Stop the recording
        /// </summary>
        public void Stop()
        {
            if (writer == null)
                throw new Exception("This recorder is already stopped");

            try
            {
                writer.Close();
                writer.Dispose();

                recordStream.Dispose();
                recordStream = null;
            }
            catch (Exception ex)
            {
            }
        }
    }
}